﻿// Copyright (C) Microsoft Corporation. All Rights Reserved.
// This code released under the terms of the Microsoft Public License
// (Ms-PL, http://opensource.org/licenses/ms-pl.html).

// ***************************************************** //
//   MODIFIED BY JOHN WESTLAKE
//
//   1 FEBRUARY 2012
//     + Improved reliability (can return String.Empty instead of failing)
//
//   2 FEBRUARY 2012
//     + Additional safe parsing methods added
// ***************************************************** //

using System;
using System.Diagnostics;
using System.Xml.Linq;

namespace Delay
{
    /// <summary>
    /// Class that exposes a variety of extension methods to make parsing XML with XLINQ easier and safer.
    /// </summary>
    static class XLinqExtensions
    {
        /// <summary>
        /// Gets the named XElement child of the specified XElement.
        /// </summary>
        /// <param name="element">Specified element.</param>
        /// <param name="name">Name of the child.</param>
        /// <returns>XElement instance.</returns>
        public static XElement SafeGetElement(this XElement element, XName name)
        {
            Debug.Assert(null != element);
            Debug.Assert(null != name);
            return element.Element(name) ?? new XElement(name, "");
        }

        /// <summary>
        /// Gets the named XAttribute of the specified XElement.
        /// </summary>
        /// <param name="element">Specified element.</param>
        /// <param name="name">Name of the attribute.</param>
        /// <returns>XAttribute instance.</returns>
        public static XAttribute SafeGetAttribute(this XElement element, XName name)
        {
            Debug.Assert(null != element);
            Debug.Assert(null != name);
            return element.Attribute(name) ?? new XAttribute(name, "");
        }

        /// <summary>
        /// Gets the string value of the specified XElement.
        /// </summary>
        /// <param name="element">Specified element.</param>
        /// <returns>String value.</returns>
        public static string SafeGetStringValueEmptyable(this XElement element)
        {
            try
            {
                // ORIGINAL CODE
                // Debug.Assert(null != element);
                // return element.Value;

                if (null != element) return element.Value;
                else return String.Empty;
            }
            catch
            {
                return String.Empty;
            }
        }

        /// <summary>
        /// Gets the string value of the specified XElement.
        /// </summary>
        /// <param name="element">Specified element.</param>
        /// <returns>String value.</returns>
        public static string SafeGetStringValue(this XElement element)
        {
            try
            {
                // ORIGINAL CODE
                Debug.Assert(null != element);
                return element.Value;
            }
            catch
            {
                return String.Empty;
            }
        }
        

        /// <summary>
        /// Gets the string value of the specified XAttribute.
        /// </summary>
        /// <param name="attribute">Specified attribute.</param>
        /// <returns>String value.</returns>
        public static string SafeGetStringValue(this XAttribute attribute)
        {
            Debug.Assert(null != attribute);
            return attribute.Value;
        }

        /// <summary>
        /// Gets the DateTime value of the specified XElement, falling back to a provided value in case of failure.
        /// </summary>
        /// <param name="element">Specified element.</param>
        /// <param name="fallback">Fallback value.</param>
        /// <returns>DateTime value.</returns>
        public static DateTime SafeGetDateTimeValue(this XElement element, DateTime fallback)
        {
            Debug.Assert(null != element);
            DateTime value;
            if (!DateTime.TryParse(element.Value, out value))
            {
                value = fallback;
            }
            return value;
        }

        /// ********************************************* ///
        /// Additional safe parsing methods, added by me  ///
        /// ********************************************* ///

        public static Int32 SafeGetInt32Value(this XElement element)
        {
            Debug.Assert(null != element);
            int value;

            try { value = Convert.ToInt32(element.Value); }
            catch { value = 0; }

            return value;
        }

        public static Int32 SafeGetInt32Value(this XAttribute attribute)
        {
            Debug.Assert(null != attribute);
            int value;

            try { value = Convert.ToInt32(attribute.Value); }
            catch { value = 0; }

            return value;
        }

        public static Int64 SafeGetInt64Value(this XElement element)
        {
            Debug.Assert(null != element);
            long value;

            try { value = Convert.ToInt64(element.Value); }
            catch { value = 0; }

            return value;
        }

        public static Int64 SafeGetInt64Value(this XAttribute attribute)
        {
            Debug.Assert(null != attribute);
            long value;

            try { value = Convert.ToInt64(attribute.Value); }
            catch { value = 0; }

            return value;
        }

        public static Uri SafeGetUriValue(this XElement element)
        {
            Uri value;

            try { value = new Uri(element.SafeGetStringValueEmptyable(), UriKind.RelativeOrAbsolute); }
            catch { value = new Uri(String.Empty, UriKind.RelativeOrAbsolute); }

            return value;
        }
    }
}
